#ifndef Base_Factory_h
#define Base_Factory_h

#include "BaseModule.h"
#include "Object.h"

SG_NAMESPACE_OPEN

namespace Base
{
    /// Abstract base class of all producers
    class BASE_EXPORT Producer
    {
      public:
        Producer ();
        virtual ~Producer ();
        /// overwritten by a concrete producer to produce the needed object
        virtual Object* Produce () const = 0;
    };

    /** Base class of all factories
     * This class has the purpose to produce instances of classes at runtime
     * that are unknown at compile time. It holds a map of so called
     * producers which are able to produce an instance of a special class.
     * Producer can be registered at runtime through e.g. application modules
     */
    class BASE_EXPORT Factory
    {
      public:
        /// construction
        Factory ();
        /// destruction
        virtual ~Factory ();

        ///  the singleton
        static Factory* GetInstance ();

        /// Adds a new prducer instance
        void AddProducer (const std::string& sClassName, Producer* pcProducer);
        /// returns true if there is a producer for this class registered
        bool CanProduce (const std::string& sClassName) const;
        /// returns a list of all registered producer
        std::list<std::string> CanProduce () const;

        /// produce a class with the given name
        void* Produce (const std::string& sClassName) const;

      protected:
        std::unordered_map<std::string, Producer*> myProducers;
    };

    /// General utility to register the ODE solver.
    template <class CLASS>
    class GeneralProducer : public Base::Producer
    {
      public:
        explicit GeneralProducer (const char* className)
        {
            Base::Factory::GetInstance ()->AddProducer (className, this);
        }
        ~GeneralProducer () override
        {}

        Object* Produce () const override
        {
            return (new CLASS);
        }
    };
}  // namespace Base

SG_NAMESPACE_CLOSE

#endif  // Base_Factory_h